﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Reflection;

using Skyhook.Core.Xml;
using Skyhook.Core.Configuration;
using Skyhook.Core.Configuration.Serialize.Attributes;

namespace Skyhook.Core.Configuration.Serialize
{
    static class XmlSerialize
    {
        const string DataXPathString = "/data[@utype='{0}']/{0}s/{0}";
        const string DataWithTypeXPathString = "/data[@utype='{0}']/{0}s/{0}[@type='{1}']";
        const string TypeAttributeName = "type";
        
        static public List<T> CreateDataList<T>(XmlDocumentWithFileName xmldoc) where T : Data, new()
        {
            string utype = GetDataUType<T>();

            List<T> datalist = new List<T>();

            XmlNodeList datanodeslist = xmldoc.Document.SelectNodes(string.Format(DataXPathString, utype));
            foreach (XmlNode datanode in datanodeslist)
            {
                T data = new T();

                data.FileName = xmldoc.FileName;
                data.Type = datanode.Attributes[TypeAttributeName].Value;

                datalist.Add(data);
            }

            return datalist;
        }

        static string GetDataUType<T>()
        {
            string utype = null;

            UTypeAttribute utypeattr = (UTypeAttribute)Attribute.GetCustomAttribute(typeof(T), typeof(UTypeAttribute));
            if (utypeattr != null)
            {
                utype = utypeattr.Name;
            }

            return utype;
        }

        static public void DeserializeDataFromCache<T>(T data, XmlDocumentsCache xmlcache) where T : Data
        {
            XmlDocumentWithFileName xmldoc = xmlcache[data.FileName];
            string utype = GetDataUType<T>();

            XmlNode datanode = xmldoc.Document.SelectSingleNode(string.Format(DataWithTypeXPathString, utype, data.Type));
            if (datanode != null)
            {
                Deserialize(data, datanode);
                data.IsLoaded = true;
            }
        }

        static void Deserialize(object data, XmlNode datanode)
        {
            /*System.Reflection.FieldInfo[] fields = data.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);

            foreach (FieldInfo field in fields)
            {

                Attribute attr = Attribute.GetCustomAttribute(field, typeof(XmlAttributeName));
                if (attr != null)
                {
                    if (field.FieldType == typeof(int))
                    {
                        field.SetValue(data, XmlHelpers.GetAttributeValue<int>(datanode, ((XmlAttributeName)attr).Name));
                    }
                    if (field.FieldType == typeof(string))
                    {
                        field.SetValue(data, XmlHelpers.GetAttributeValue<string>(datanode, ((XmlAttributeName)attr).Name));
                    }
                    if (field.FieldType == typeof(bool))
                    {
                        field.SetValue(data, XmlHelpers.GetAttributeValue<bool>(datanode, ((XmlAttributeName)attr).Name));
                    }
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlNodeName));
                if (attr != null)
                {
                    field.SetValue(data, datanode.Name);
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlInnerText));
                if (attr != null)
                {
                    if (field.FieldType == typeof(int))
                    {
                        field.SetValue(data, int.Parse(datanode.InnerText));
                    }
                    if (field.FieldType == typeof(string))
                    {
                        field.SetValue(data, datanode.InnerText);
                    }
                    if (field.FieldType == typeof(bool))
                    {
                        field.SetValue(data, bool.Parse(datanode.InnerText));
                    }
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlInnerCDATAText));
                if (attr != null)
                {
                    if (field.FieldType == typeof(int))
                    {
                        field.SetValue(data, int.Parse(datanode.FirstChild.Value));
                    }
                    if (field.FieldType == typeof(string))
                    {
                        field.SetValue(data, datanode.FirstChild.Value);
                    }
                    if (field.FieldType == typeof(bool))
                    {
                        field.SetValue(data, bool.Parse(datanode.InnerText));
                    }
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlListToStringAttributeName));
                if (attr != null)
                {
                    string listattr = XmlHelpers.GetAttributeValue<string>(datanode, ((XmlListToStringAttributeName)attr).Name);
                    if (listattr != null)
                    {
                        char[] delimiters = { ',' };
                        string[] strings = listattr.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);

                        foreach (string str in strings)
                        {
                            if (field.FieldType.GetGenericArguments()[0] == typeof(int))
                            {
                                ((System.Collections.IList)field.GetValue(data)).Add(int.Parse(str));
                            }
                            if (field.FieldType.GetGenericArguments()[0] == typeof(string))
                            {
                                ((System.Collections.IList)field.GetValue(data)).Add(str);
                            }
                            if (field.FieldType.GetGenericArguments()[0] == typeof(bool))
                            {
                                ((System.Collections.IList)field.GetValue(data)).Add(bool.Parse(str));
                            }
                        }
                    }
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlListToStringDataTypeAttributeName));
                if (attr != null)
                {
                    string listattr = XmlHelpers.GetAttributeValue<string>(datanode, ((XmlListToStringDataTypeAttributeName)attr).Name);
                    if (listattr != null)
                    {
                        char[] delimiters = { ',' };
                        string[] strings = listattr.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);

                        foreach (string str in strings)
                        {
                            ((System.Collections.IList)field.GetValue(data)).Add(Paradise.Data.DataConfiguration.Instance.GetData(field.FieldType.GetGenericArguments()[0], str));
                        }
                    }
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlNodeWithAttributeNames));
                if (attr != null)
                {
                    XmlNode node = datanode.SelectSingleNode("./" + ((XmlNodeWithAttributeNames)attr).NodeName);
                    if (node != null)
                    {
                        if (field.FieldType == typeof(int))
                        {
                            field.SetValue(data, XmlHelpers.GetAttributeValue<int>(node, ((XmlNodeWithAttributeNames)attr).AttributeName));
                        }
                        if (field.FieldType == typeof(string))
                        {
                            field.SetValue(data, XmlHelpers.GetAttributeValue<string>(node, ((XmlNodeWithAttributeNames)attr).AttributeName));
                        }
                        if (field.FieldType == typeof(bool))
                        {
                            field.SetValue(data, XmlHelpers.GetAttributeValue<bool>(node, ((XmlNodeWithAttributeNames)attr).AttributeName));
                        }
                    }
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlAttributeDataTypeName));
                if (attr != null)
                {
                    string datatype = XmlHelpers.GetAttributeValue<string>(datanode, ((XmlAttributeDataTypeName)attr).Name);
                    if (datatype != null)
                    {
                        object linkeddata = DataConfiguration.Instance.GetData(field.FieldType, datatype);
                        if (linkeddata == null)
                        {
                            Console.WriteLine("Error while deserializing " + data.GetType().ToString() + " : " + field.GetType().ToString() + " with type " + datatype + " not found");
                        }
                        field.SetValue(data, linkeddata);
                    }
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlInnerTextDataType));
                if (attr != null)
                {
                    string datatype = datanode.InnerText;
                    if (datatype != null)
                    {
                        object linkeddata = DataConfiguration.Instance.GetData(field.FieldType, datatype);
                        if (linkeddata == null)
                        {
                            Console.WriteLine("Error while deserializing " + data.GetType().ToString() + " : " + field.GetType().ToString() + " with type " + datatype + " not found");
                        }
                        field.SetValue(data, linkeddata);
                    }
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlNodeDataTypeName));
                if (attr != null)
                {
                    string datatype = datanode.Name;
                    object linkeddata = DataConfiguration.Instance.GetData(field.FieldType, datatype);
                    if (linkeddata == null)
                    {
                        Console.WriteLine("Error while deserializing " + data.GetType().ToString() + " : " + field.GetType().ToString() + " with type " + datatype + " not found");
                    }
                    field.SetValue(data, linkeddata);
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlSerializeChildNodes));
                if (attr != null)
                {
                    Type childrentype = field.FieldType.GetGenericArguments()[0];
                    XmlNodeList childnodes = null;
                    string childnodename = null;

                    string parentchildname = ((XmlSerializeChildNodes)attr).Name;
                    if (parentchildname != null)
                    {
                        childnodename = parentchildname;
                    }
                    else
                    {
                        childnodename = GetNodeName(childrentype, null);
                    }

                    if (childnodename == null)
                    {
                        childnodes = datanode.SelectNodes("./*");
                    }
                    else
                    {
                        childnodes = datanode.SelectNodes("./" + childnodename);
                    }
                    foreach (XmlNode childnode in childnodes)
                    {
                        object child = null;
                        if (((XmlSerializeChildNodes)attr).Factory != null)
                        {
                            child = ((XmlSerializeChildNodes)attr).Factory.Create(childnode.Attributes["type"].Value);
                        }
                        else
                        {
                            ConstructorInfo childconstructor = childrentype.GetConstructor(System.Type.EmptyTypes);
                            child = childconstructor.Invoke(null);
                        }
                        Deserialize(childnode, child);
                        ((System.Collections.IList)field.GetValue(data)).Add(child);
                    }
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlSerializeSingleChildNode));
                if (attr != null)
                {
                    Type childrentype = field.FieldType;
                    XmlNode childnode = null;

                    string childnodename = null;
                    string parentchildname = ((XmlSerializeSingleChildNode)attr).Name;
                    if (parentchildname != null)
                    {
                        childnodename = parentchildname;
                    }
                    else
                    {
                        childnodename = GetNodeName(childrentype, null);
                    }

                    if (childnodename == null)
                    {
                        childnode = datanode.SelectSingleNode("./*");
                    }
                    else
                    {
                        childnode = datanode.SelectSingleNode("./" + childnodename);
                    }

                    if (childnode != null)
                    {
                        object child = null;
                        if (((XmlSerializeSingleChildNode)attr).Factory != null)
                        {
                            child = ((XmlSerializeSingleChildNode)attr).Factory.Create(childnode.Attributes["type"].Value);
                        }
                        else
                        {
                            ConstructorInfo childconstructor = childrentype.GetConstructor(System.Type.EmptyTypes);
                            child = childconstructor.Invoke(null);
                        }
                        Deserialize(childnode, child);
                        field.SetValue(data, child);
                    }
                }
            }*/
        }
        /*
        static public XmlNode Serialize(object data, XmlDocument xmldoc, string parentnodename = null)
        {
            XmlNode newnode = null;

            string nodename = null;

            if (parentnodename != null)
            {
                nodename = parentnodename;
            }
            else
            {
                nodename = GetNodeName(data.GetType(), data);
            }

            if (nodename == null)
            {
                return null;
            }

            System.Reflection.FieldInfo[] fields = data.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
            System.Reflection.PropertyInfo[] properties = data.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);

            newnode = xmldoc.CreateNode(XmlNodeType.Element, nodename, "");

            Attribute nodenameattr = Attribute.GetCustomAttribute(data.GetType(), typeof(XmlNodeDataTypeName));
            if (nodenameattr == null)
            {
                foreach (FieldInfo field in fields)
                {
                    Attribute attr = Attribute.GetCustomAttribute(field, typeof(XmlTypeAttribute));
                    if (attr != null)
                    {
                        AddAttributeAndSetValue(newnode, ((XmlTypeAttribute)attr).Name, field.GetValue(data));
                    }
                }

                foreach (PropertyInfo property in properties)
                {
                    Attribute attr = Attribute.GetCustomAttribute(property, typeof(XmlTypeAttribute));
                    if (attr != null)
                    {
                        AddAttributeAndSetValue(newnode, ((XmlTypeAttribute)attr).Name, property.GetValue(data, null));
                    }
                }
            }

            foreach (FieldInfo field in fields)
            {
                Attribute attr = Attribute.GetCustomAttribute(field, typeof(XmlAttributeName));
                if (attr != null)
                {
                    AddAttributeAndSetValue(newnode, ((XmlAttributeName)attr).Name, field.GetValue(data));
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlInnerText));
                if (attr != null)
                {
                    newnode.InnerText = field.GetValue(data).ToString();
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlInnerCDATAText));
                if (attr != null)
                {
                    XmlNode cdata = xmldoc.CreateCDataSection(field.GetValue(data).ToString());
                    newnode.AppendChild(cdata);
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlListToStringAttributeName));
                if (attr != null)
                {
                    System.Collections.IList list = (System.Collections.IList)field.GetValue(data);

                    List<string> strings = new List<string>();

                    foreach (object value in list)
                    {
                        strings.Add(value.ToString());
                    }

                    if (strings.Count > 0)
                    {
                        AddAttributeAndSetValue(newnode, ((XmlListToStringAttributeName)attr).Name, string.Join(",", strings.ToArray()));
                    }
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlListToStringDataTypeAttributeName));
                if (attr != null)
                {
                    System.Collections.IList list = (System.Collections.IList)field.GetValue(data);

                    List<string> strings = new List<string>();

                    foreach (object value in list)
                    {
                        strings.Add(((Paradise.Data.Data)value).Type);
                    }

                    if (strings.Count > 0)
                    {
                        AddAttributeAndSetValue(newnode, ((XmlListToStringDataTypeAttributeName)attr).Name, string.Join(",", strings.ToArray()));
                    }
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlNodeWithAttributeNames));
                if (attr != null)
                {
                    if (field.FieldType == typeof(int))
                    {
                        if ((int)(field.GetValue(data)) != 0)
                        {
                            XmlNode node = xmldoc.CreateNode(XmlNodeType.Element, ((XmlNodeWithAttributeNames)attr).NodeName, "");
                            newnode.AppendChild(node);

                            AddAttributeAndSetValue(node, ((XmlNodeWithAttributeNames)attr).AttributeName, field.GetValue(data));
                        }
                    }
                    if (field.FieldType == typeof(string))
                    {
                        if ((string)(field.GetValue(data)) != null)
                        {
                            XmlNode node = xmldoc.CreateNode(XmlNodeType.Element, ((XmlNodeWithAttributeNames)attr).NodeName, "");
                            newnode.AppendChild(node);

                            AddAttributeAndSetValue(node, ((XmlNodeWithAttributeNames)attr).AttributeName, field.GetValue(data));
                        }
                    }
                    if (field.FieldType == typeof(bool))
                    {
                        if ((bool)(field.GetValue(data)) != false)
                        {
                            XmlNode node = xmldoc.CreateNode(XmlNodeType.Element, ((XmlNodeWithAttributeNames)attr).NodeName, "");
                            newnode.AppendChild(node);

                            AddAttributeAndSetValue(node, ((XmlNodeWithAttributeNames)attr).AttributeName, field.GetValue(data));
                        }
                    }
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlAttributeDataTypeName));
                if (attr != null)
                {
                    if (field.GetValue(data) != null)
                    {
                        AddAttributeAndSetValue(newnode, ((XmlAttributeDataTypeName)attr).Name, ((Paradise.Data.Data)field.GetValue(data)).Type);
                    }
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlInnerTextDataType));
                if (attr != null)
                {
                    if (field.GetValue(data) != null)
                    {
                        newnode.InnerText = ((Paradise.Data.Data)field.GetValue(data)).Type;
                    }
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlSerializeChildNodes));
                if (attr != null)
                {
                    System.Collections.IList children = (System.Collections.IList)field.GetValue(data);
                    foreach (object child in children)
                    {
                        newnode.AppendChild(Serialize(child, xmldoc, ((XmlSerializeChildNodes)attr).Name));
                    }
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlSerializeSingleChildNode));
                if (attr != null)
                {
                    object child = field.GetValue(data);
                    if (child != null)
                    {
                        newnode.AppendChild(Serialize(child, xmldoc, ((XmlSerializeSingleChildNode)attr).Name));
                    }
                }
            }

            return newnode;
        }

        static private void AddAttributeAndSetValue(XmlNode node, string name, object value)
        {
            if (value == null)
            {
                return;
            }
            if (value.GetType() == typeof(int))
            {
                XmlHelpers.AddAttributeAndSetValue(node, name, (int)value);
                return;
            }
            if (value.GetType() == typeof(string))
            {
                XmlHelpers.AddAttributeAndSetValue(node, name, (string)value);
                return;
            }
            if (value.GetType() == typeof(bool))
            {
                XmlHelpers.AddAttributeAndSetValue(node, name, (bool)value);
                return;
            }

            XmlHelpers.AddAttributeAndSetValue(node, name, (IConvertible)value);
        }

        static public void Deserialize(XmlNode datanode, object data)
        {
            System.Reflection.FieldInfo[] fields = data.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);

            foreach (FieldInfo field in fields)
            {

                Attribute attr = Attribute.GetCustomAttribute(field, typeof(XmlAttributeName));
                if (attr != null)
                {
                    if (field.FieldType == typeof(int))
                    {
                        field.SetValue(data, XmlHelpers.GetAttributeValue<int>(datanode, ((XmlAttributeName)attr).Name));
                    }
                    if (field.FieldType == typeof(string))
                    {
                        field.SetValue(data, XmlHelpers.GetAttributeValue<string>(datanode, ((XmlAttributeName)attr).Name));
                    }
                    if (field.FieldType == typeof(bool))
                    {
                        field.SetValue(data, XmlHelpers.GetAttributeValue<bool>(datanode, ((XmlAttributeName)attr).Name));
                    }
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlNodeName));
                if (attr != null)
                {
                    field.SetValue(data, datanode.Name);
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlInnerText));
                if (attr != null)
                {
                    if (field.FieldType == typeof(int))
                    {
                        field.SetValue(data, int.Parse(datanode.InnerText));
                    }
                    if (field.FieldType == typeof(string))
                    {
                        field.SetValue(data, datanode.InnerText);
                    }
                    if (field.FieldType == typeof(bool))
                    {
                        field.SetValue(data, bool.Parse(datanode.InnerText));
                    }
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlInnerCDATAText));
                if (attr != null)
                {
                    if (field.FieldType == typeof(int))
                    {
                        field.SetValue(data, int.Parse(datanode.FirstChild.Value));
                    }
                    if (field.FieldType == typeof(string))
                    {
                        field.SetValue(data, datanode.FirstChild.Value);
                    }
                    if (field.FieldType == typeof(bool))
                    {
                        field.SetValue(data, bool.Parse(datanode.InnerText));
                    }
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlListToStringAttributeName));
                if (attr != null)
                {
                    string listattr = XmlHelpers.GetAttributeValue<string>(datanode, ((XmlListToStringAttributeName)attr).Name);
                    if (listattr != null)
                    {
                        char[] delimiters = { ',' };
                        string[] strings = listattr.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);

                        foreach (string str in strings)
                        {
                            if (field.FieldType.GetGenericArguments()[0] == typeof(int))
                            {
                                ((System.Collections.IList)field.GetValue(data)).Add(int.Parse(str));
                            }
                            if (field.FieldType.GetGenericArguments()[0] == typeof(string))
                            {
                                ((System.Collections.IList)field.GetValue(data)).Add(str);
                            }
                            if (field.FieldType.GetGenericArguments()[0] == typeof(bool))
                            {
                                ((System.Collections.IList)field.GetValue(data)).Add(bool.Parse(str));
                            }
                        }
                    }
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlListToStringDataTypeAttributeName));
                if (attr != null)
                {
                    string listattr = XmlHelpers.GetAttributeValue<string>(datanode, ((XmlListToStringDataTypeAttributeName)attr).Name);
                    if (listattr != null)
                    {
                        char[] delimiters = { ',' };
                        string[] strings = listattr.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);

                        foreach (string str in strings)
                        {
                            ((System.Collections.IList)field.GetValue(data)).Add(Paradise.Data.DataConfiguration.Instance.GetData(field.FieldType.GetGenericArguments()[0], str));
                        }
                    }
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlNodeWithAttributeNames));
                if (attr != null)
                {
                    XmlNode node = datanode.SelectSingleNode("./" + ((XmlNodeWithAttributeNames)attr).NodeName);
                    if (node != null)
                    {
                        if (field.FieldType == typeof(int))
                        {
                            field.SetValue(data, XmlHelpers.GetAttributeValue<int>(node, ((XmlNodeWithAttributeNames)attr).AttributeName));
                        }
                        if (field.FieldType == typeof(string))
                        {
                            field.SetValue(data, XmlHelpers.GetAttributeValue<string>(node, ((XmlNodeWithAttributeNames)attr).AttributeName));
                        }
                        if (field.FieldType == typeof(bool))
                        {
                            field.SetValue(data, XmlHelpers.GetAttributeValue<bool>(node, ((XmlNodeWithAttributeNames)attr).AttributeName));
                        }
                    }
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlAttributeDataTypeName));
                if (attr != null)
                {
                    string datatype = XmlHelpers.GetAttributeValue<string>(datanode, ((XmlAttributeDataTypeName)attr).Name);
                    if (datatype != null)
                    {
                        object linkeddata = DataConfiguration.Instance.GetData(field.FieldType, datatype);
                        if (linkeddata == null)
                        {
                            Console.WriteLine("Error while deserializing " + data.GetType().ToString() + " : " + field.GetType().ToString() + " with type " + datatype + " not found");
                        }
                        field.SetValue(data, linkeddata);
                    }
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlInnerTextDataType));
                if (attr != null)
                {
                    string datatype = datanode.InnerText;
                    if (datatype != null)
                    {
                        object linkeddata = DataConfiguration.Instance.GetData(field.FieldType, datatype);
                        if (linkeddata == null)
                        {
                            Console.WriteLine("Error while deserializing " + data.GetType().ToString() + " : " + field.GetType().ToString() + " with type " + datatype + " not found");
                        }
                        field.SetValue(data, linkeddata);
                    }
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlNodeDataTypeName));
                if (attr != null)
                {
                    string datatype = datanode.Name;
                    object linkeddata = DataConfiguration.Instance.GetData(field.FieldType, datatype);
                    if (linkeddata == null)
                    {
                        Console.WriteLine("Error while deserializing " + data.GetType().ToString() + " : " + field.GetType().ToString() + " with type " + datatype + " not found");
                    }
                    field.SetValue(data, linkeddata);
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlSerializeChildNodes));
                if (attr != null)
                {
                    Type childrentype = field.FieldType.GetGenericArguments()[0];
                    XmlNodeList childnodes = null;
                    string childnodename = null;

                    string parentchildname = ((XmlSerializeChildNodes)attr).Name;
                    if (parentchildname != null)
                    {
                        childnodename = parentchildname;
                    }
                    else
                    {
                        childnodename = GetNodeName(childrentype, null);
                    }

                    if (childnodename == null)
                    {
                        childnodes = datanode.SelectNodes("./*");
                    }
                    else
                    {
                        childnodes = datanode.SelectNodes("./" + childnodename);
                    }
                    foreach (XmlNode childnode in childnodes)
                    {
                        object child = null;
                        if (((XmlSerializeChildNodes)attr).Factory != null)
                        {
                            child = ((XmlSerializeChildNodes)attr).Factory.Create(childnode.Attributes["type"].Value);
                        }
                        else
                        {
                            ConstructorInfo childconstructor = childrentype.GetConstructor(System.Type.EmptyTypes);
                            child = childconstructor.Invoke(null);
                        }
                        Deserialize(childnode, child);
                        ((System.Collections.IList)field.GetValue(data)).Add(child);
                    }
                }

                attr = Attribute.GetCustomAttribute(field, typeof(XmlSerializeSingleChildNode));
                if (attr != null)
                {
                    Type childrentype = field.FieldType;
                    XmlNode childnode = null;

                    string childnodename = null;
                    string parentchildname = ((XmlSerializeSingleChildNode)attr).Name;
                    if (parentchildname != null)
                    {
                        childnodename = parentchildname;
                    }
                    else
                    {
                        childnodename = GetNodeName(childrentype, null);
                    }

                    if (childnodename == null)
                    {
                        childnode = datanode.SelectSingleNode("./*");
                    }
                    else
                    {
                        childnode = datanode.SelectSingleNode("./" + childnodename);
                    }

                    if (childnode != null)
                    {
                        object child = null;
                        if (((XmlSerializeSingleChildNode)attr).Factory != null)
                        {
                            child = ((XmlSerializeSingleChildNode)attr).Factory.Create(childnode.Attributes["type"].Value);
                        }
                        else
                        {
                            ConstructorInfo childconstructor = childrentype.GetConstructor(System.Type.EmptyTypes);
                            child = childconstructor.Invoke(null);
                        }
                        Deserialize(childnode, child);
                        field.SetValue(data, child);
                    }
                }
            }
        }

        static private string GetNodeName(Type type, object data)
        {
            string nodename = null;

            Attribute nodenameattr = Attribute.GetCustomAttribute(type, typeof(XmlNodeName));
            if (nodenameattr != null)
            {
                nodename = ((XmlNodeName)nodenameattr).Name;
            }

            if (data != null)
            {
                nodenameattr = Attribute.GetCustomAttribute(type, typeof(XmlNodeDataTypeName));
                if (nodenameattr != null)
                {
                    nodename = ((Paradise.Data.Data)data).Type;
                }

                FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);

                foreach (FieldInfo field in fields)
                {

                    Attribute attr = Attribute.GetCustomAttribute(field, typeof(XmlNodeName));
                    if (attr != null)
                    {
                        nodename = field.GetValue(data).ToString();
                    }

                    attr = Attribute.GetCustomAttribute(field, typeof(XmlNodeDataTypeName));
                    if (attr != null)
                    {
                        nodename = ((Paradise.Data.Data)field.GetValue(data)).Type;
                    }
                }
            }

            return nodename;
        }*/
    }
}
